// AST树转 render函数

/*
  <div id="app" style="color: red;font-size: 20px;">
    hello, {{ name }}
    <span class="text" style="color: green;">{{age}}</span>
  </div>

  _c() => createElement() // 创建元素
  _v() => createTextNode() // 创建文本节点
  _s() => {{name}} => _s(name) // (遇到双大括号)获取真实数据

  function render() {
    return `
      _c( // 元素
        "div", // 标签
        { // 属性
          "id": "app",
          "style": {
            "color": "red",
            "font-size": "20px"
          }
        },
        _v("hello, " + _s(name)), // 文本
        _c( // 子元素
          "span",
          {
            "class": "text",
            "style": {
              "color": "green"
            }
          },
          _v(_s(age))
        )
      )
    `
  }
*/

const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g; // 匹配双括号里的内容

function formatProps(attrs) { // 格式化属性
  let attrStr = ''; // 因为是要拼接到code 里 需要转字符串

  for (let i = 0; i < attrs.length; i ++) {
    let attr = attrs[i];

    if (attr.name === 'style') {
      // 'color: red;font-size: 20px;' 转对象
      let styleAttrs = {};

      attr.value.split(';').map(styleAttr => {
        let [key, value] = styleAttr.split(':');
        styleAttrs[key] = value;
      })
      attr.value = styleAttrs;
    }

    attrStr += `${attr.name}: ${JSON.stringify(attr.value)},`;
  }

  // console.log(`{${ attrStr.slice(0, -1) }}`);

  return `{${ attrStr.slice(0, -1) }}`; // 还需要把最后一个逗号去掉
}

function generateChild(node) { // 递归处理子元素内容(拼接字符串)
  if (node.type === 1) { // 元素节点
    return generate(node);
  } else if (node.type === 3) { // 文本节点
    let text = node.text;

    if (!defaultTagRE.test(text)) { // 如果是没有双括号(纯文本)
      return `_v(${JSON.stringify(text)})`;
    }

    // 处理含有双括号的文本
    let match,
        index,
    // 因为正则带有修饰符g 需要注意lastIndex的问题 每次循环不同的{{}} 时需要置零
        lastIndex = defaultTagRE.lastIndex = 0,
        textArr = [];

    while (match = defaultTagRE.exec(text)) {
      // console.log('match', match);

      index = match.index; // 保存匹配开始index

      if (index > lastIndex) { // 遇到双括号，把前面的内容截取出来
        textArr.push(JSON.stringify(text.slice(lastIndex, index)));
      }

      textArr.push(`_s(${ match[1].trim() })`); // 双括号里面的内容

      lastIndex = index + match[0].length; // 重置lastIndex(因为是要通过与index相比较)
    }

    if (lastIndex < text.length) { // 如果小于text的长度说明后面还有内容(纯文本)
      textArr.push(JSON.stringify(text.slice(lastIndex)));
    }

    // console.log(`_v(${textArr.join('+')})`);

    return `_v(${textArr.join('+')})`;
  }
}

function getChildren(el) { // 处理子元素
  const children = el.children;

  if (children) {
    return children.map(c => generateChild(c)).join(','); // 最后需要加逗号
  }
}

function generate(el) {
  let children = getChildren(el); // 获取到子元素

  let code = `_c(
    '${ el.tag }',
    ${
      el.attrs.length > 0
      ?
      `${ formatProps(el.attrs) }`
      :
      'undefined'
    }
    ${
      children ? `,${ children }` : ''
    })`;

  return code;
}

export {
  generate
}